#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

static double _curve_length(const std::vector<cv::Point>& curve, bool is_closed) {
    int numPts = curve.size();
    if (numPts <= 1) {
        return 0;
    }
    
    double length = 0;
    int last = (is_closed ? numPts-1 : 0);
    cv::Point xy_k = curve[last];
    for (int i = 0; i < numPts; i++) {
        cv::Point xy_k1 = curve[i];
        float dx = xy_k1.x - xy_k.x;
        float dy = xy_k1.y - xy_k.y;
        length += std::sqrt(dx*dx + dy*dy);
        xy_k = xy_k1;
    }
    return length;
}


int main(int argc, char **argv) {
    cv::Mat src = cv::imread("/home/xlll/Downloads/opencv/samples/data/detect_blob.png", cv::IMREAD_GRAYSCALE);
    if (src.empty()) {
        std::cout << "failed to read image" << std::endl;
        return EXIT_FAILURE;
    }
    
    cv::Mat binary;
    cv::Canny(src, binary, 100, 200);
    
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(binary, contours, cv::RETR_TREE, cv::CHAIN_APPROX_NONE, cv::Point());
    cv::RNG rng(100);
    cv::Mat drawing = cv::Mat::zeros(src.size(), CV_8UC3);
    bool is_closed = true;
    bool allSame = true;
    for (int i = 0; i < contours.size(); i++) {
        cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
        cv::drawContours(drawing, contours, i, color, 1, 8, hierarchy);
        double len1 = cv::arcLength(contours[i], is_closed);
        double len2 = _curve_length(contours[i], is_closed);
        if (std::abs(len1-len2) > DBL_EPSILON) {
            std::cout << "two results are not the same!" << std::endl;
            std::cout << "\tOpenCV --> length of contour " << i << " = " << len1 << std::endl;
            std::cout << "\tNot OpenCV --> length of contour " << i << " = " << len2 << std::endl;
            allSame = false;
        } else {
            std::cout << "tow results are the same!" << std::endl;
            std::cout << "\tlength of contour " << i << " = " << len1 << std::endl;
        }
    }
    
    std::cout << "===================================" << std::endl;
    if (!allSame) {
        std::cout << "some results are not the same!" << std::endl;
    } else {
        std::cout << "all results are the same!" << std::endl;
    }
    
    cv::imshow("binary", binary);
    cv::imshow("drawing", drawing);
    cv::waitKey(0);
    return 0;
}
